#!/bin/bash

if [ ! $# -eq 2 ]; then
	echo "Usage: $0 <config_file> <build ID>"
	exit 1
fi

BUILDID=$2

SCRIPTDIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

source $SCRIPTDIR/args.sh
source $SCRIPTDIR/func.sh

WORKDIR=$SCRIPTDIR/../../..
MULOG=$SCRIPTDIR/../mulog.py

SAVE_ARTIFACTS=0

declare log_pid

# servers to kill on exit
KILL_ON_EXIT_PIDS=()

MAKE="make -j$NUM_CPUS"

export AMT_PASSWORD=$AMT_PASSWORD
export BUILD_OUTPUT_VERBOSE=1
export BUILD_OUTPUT_NOCOLOR=1

trap cleanup EXIT

acquire_file_lock()
{
	while [ -f $LOCK ]; do
		log "$0 already running with PID `cat $LOCK`, waiting ..."
		sleep 10
	done

	echo $$ > $LOCK
}

release_file_lock()
{
	if [ `cat $LOCK` -eq $$ ]; then
		rm -f $LOCK
	fi
}

cleanup()
{
	for pid in ${KILL_ON_EXIT_PIDS[@]}; do
		kill -kill $pid >>$LOGFILE 2>&1 || true
	done
	release_file_lock
}

save_artifacts()
{
	cp $WORKDIR/emulate/bochsout.txt $LOGDIR >>$LOGFILE 2>&1
	cp $WORKDIR/emulate/emulate.out $LOGDIR >>$LOGFILE 2>&1
	cp $WORKDIR/emulate/serial.out $LOGDIR >>$LOGFILE 2>&1
}

passed()
{
	log "State -> PASSED"
	exit 0
}

failed()
{
	log "State -> FAILED"
	if [ $SAVE_ARTIFACTS -ne 0 ]; then
		save_artifacts
	fi
	exit 1
}

expect()
{
	local file=$1
	local pattern=$2
	log "Expect pattern '$pattern' in file '$file'"
	$MULOG $file | grep "$pattern" >>$LOGFILE 2>&1
	if [ $? -ne 0 ]; then
		log "Expected pattern '$pattern' not found in '$file'"
		failed
	fi
}

expect_from_file()
{
	local pattern_file=$1
	local path=$2

	while IFS= read -r line
	do
		local file=`echo "$line" | cut -d\; -f1`
		local pattern=`echo "$line" | cut -d\; -f2`
		if [ -z "$file" ]; then
			continue
		fi

		expect $path/$file "$pattern"
	done < $pattern_file
}

file_exists()
{
	if [ ! -f $1 ]; then
		log "File '$1' does not exist"
		failed
	fi
}

basename_noext()
{
	fname=${1##*/}
	echo ${fname%.*}
}

hw_targetlogdir()
{
	local system=$(basename_noext $1)
	local hardware=$(basename_noext $2)

	echo $LOGDIR/$system-$hardware
}

bochs_emulate()
{
	for i in $(seq 1 3); do
		SAVE_ARTIFACTS=1
		execute "$MAKE emulate"
		execute "sleep $BOOTWAIT_BOCHS"
		save_artifacts
		SAVE_ARTIFACTS=0

		if [ "`cat $LOGDIR/serial.out | grep ENTRY_TRAMPOLINE`" == "" ]; then
			break;
		fi
		# See Bochs bug #1400
		log "Bochs hit ENTRY_TRAMPOLINE problem, retrying ..."
		tramp_img=$(mktemp $ROOT/muen-bochs.XXXXXX.img)
		cp pack/obj/muen.img $tramp_img
		log "Saved image to '$tramp_img' for debugging"

		execute "$MAKE -C emulate clean"
	done

	execute "$MAKE -C emulate clean"

	expect_from_file $SCRIPTDIR/expect.common "$LOGDIR"
	expect_from_file $SCRIPTDIR/expect.bochs "$LOGDIR"
}

capture_output()
{
	local target_logdir=$1
	local cmd=$2

	cat >(sh -c "$cmd" > $target_logdir/serial.out 2>&1) &
	log_pid=$!
	KILL_ON_EXIT_PIDS+=$log_pid
}

hw_deploy()
{
	local target_logdir=$1
	local system=$2
	local hardware=$3
	local intscr=$4
	local expect=$5

	execute "$MAKE -C kernel clean"
	execute "$MAKE deploy HARDWARE=$hardware SYSTEM=$system"

	# be sure that power cycle is complete if target was already running
	execute "sleep 3"

	date -u +%Y%m%d > $ROOT/current_date
	cd $ROOT; python -m SimpleHTTPServer 10000 >$target_logdir/http.out 2>&1 &
	local pid_http=$!
	KILL_ON_EXIT_PIDS+=($pid_http)
	cd $WORKDIR

	# copy target scripts, retry first connect until ssh server is up on target
	execute "$SSH -o ConnectionAttempts=20 -i $SSH_KEY $LNX1_LOGIN mkdir -p /usr/local/bin"
	execute "$SCP -i $SSH_KEY $SCRIPTDIR/target_scripts/* $LNX1_LOGIN:/usr/local/bin"
	execute "$SSH -i $SSH_KEY $LNX1_LOGIN $SSH $LNX2_LOGIN mkdir -p /usr/local/bin"
	execute "$SSH -i $SSH_KEY $LNX1_LOGIN $SCP /usr/local/bin $LNX2_LOGIN:/usr/local"

	# execute configured integration script
	execute "$SSH -i $SSH_KEY $LNX1_LOGIN $integscript"

	# give serial output some time to reach the target logdir
	execute "sleep 2"

	kill $log_pid >>$LOGFILE 2>&1
	kill $pid_http >>$LOGFILE 2>&1

	execute "$MAKE -C deploy shutdown"
	execute "$MAKE -C deploy clean"

	expect_from_file $SCRIPTDIR/expect.common "$target_logdir"
	expect_from_file $SCRIPTDIR/expect.hw_common "$target_logdir"

	if [ ! -z "$expect" ]; then
		file_exists $SCRIPTDIR/$expect
		expect_from_file $SCRIPTDIR/$expect "$target_logdir"
	fi
}

deploy_to_hardware()
{
	for item in ${TARGETS[@]}; do
		ip=`echo $item | cut -d\; -f1`
		system=`echo $item | cut -d\; -f2`
		hardware=`echo $item | cut -d\; -f3`
		integscript=`echo $item | cut -d\; -f4`
		expect=`echo $item | cut -d\; -f5`
		target_logdir=$(hw_targetlogdir "$system" "$hardware")
		execute "mkdir -p $target_logdir"

		log "Deploying system '$system' to hardware '$hardware'"
		if [ -z "$ip" ]; then
			# power bar with xhci debug
			log "Using EPC power mechanism"
			export TARGET_PWR_MECH=epc
			capture_output $target_logdir "$LOG_CMD_XHCI"
		else
			# Intel AMT
			log "Using Intel AMT power mechanism for target IP $ip"
			export TARGET_PWR_MECH=amt
			export TARGET_IP=$ip
			execute "ping -c 6 $ip"
			capture_output $target_logdir "$LOG_CMD_AMT $ip"
		fi

		hw_deploy $target_logdir $system $hardware $integscript $expect
	done
}

generate_metrics()
{
	execute "make -C kernel metrics"
}

mkdir -p $LOGDIR

echo "Logging to file $LOGFILE"

acquire_file_lock

execute "cd $WORKDIR"
execute "$MAKE -C deploy clean"

bochs_emulate
deploy_to_hardware
generate_metrics

passed
